{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Battery Electric Vehicle Charging\n",
    "\n",
    "In this example a battery electric vehicle (BEV) is driven 100 km in the morning and 100 km in the evening, to simulate commuting, and charged during the day by a solar panel at the driver's place of work. The size of the panel is computed by the optimisation.\n",
    "\n",
    "The BEV has a battery of size 100 kWh and an electricity consumption of 0.18 kWh/km.\n",
    "\n",
    "**NB:** this example will use units of kW and kWh, unlike the PyPSA defaults"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pypsa\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# use 24 hour period for consideration\n",
    "index = pd.date_range(\"2016-01-01 00:00\", \"2016-01-01 23:00\", freq=\"H\")\n",
    "\n",
    "# consumption pattern of BEV\n",
    "bev_usage = pd.Series([0.0] * 7 + [9.0] * 2 + [0.0] * 8 + [9.0] * 2 + [0.0] * 5, index)\n",
    "\n",
    "# solar PV panel generation per unit of capacity\n",
    "pv_pu = pd.Series(\n",
    "    [0.0] * 7\n",
    "    + [0.2, 0.4, 0.6, 0.75, 0.85, 0.9, 0.85, 0.75, 0.6, 0.4, 0.2, 0.1]\n",
    "    + [0.0] * 5,\n",
    "    index,\n",
    ")\n",
    "\n",
    "# availability of charging - i.e. only when parked at office\n",
    "charger_p_max_pu = pd.Series(0, index=index)\n",
    "charger_p_max_pu[\"2016-01-01 09:00\":\"2016-01-01 16:00\"] = 1.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.concat({\"BEV\": bev_usage, \"PV\": pv_pu, \"Charger\": charger_p_max_pu}, axis=1)\n",
    "df.plot.area(subplots=True, figsize=(10, 7))\n",
    "plt.tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Initialize the network"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "network = pypsa.Network()\n",
    "network.set_snapshots(index)\n",
    "\n",
    "network.add(\"Bus\", \"place of work\", carrier=\"AC\")\n",
    "\n",
    "network.add(\"Bus\", \"battery\", carrier=\"Li-ion\")\n",
    "\n",
    "network.add(\n",
    "    \"Generator\",\n",
    "    \"PV panel\",\n",
    "    bus=\"place of work\",\n",
    "    p_nom_extendable=True,\n",
    "    p_max_pu=pv_pu,\n",
    "    capital_cost=1000.0,\n",
    ")\n",
    "\n",
    "network.add(\"Load\", \"driving\", bus=\"battery\", p_set=bev_usage)\n",
    "\n",
    "network.add(\n",
    "    \"Link\",\n",
    "    \"charger\",\n",
    "    bus0=\"place of work\",\n",
    "    bus1=\"battery\",\n",
    "    p_nom=120,  # super-charger with 120 kW\n",
    "    p_max_pu=charger_p_max_pu,\n",
    "    efficiency=0.9,\n",
    ")\n",
    "\n",
    "\n",
    "network.add(\"Store\", \"battery storage\", bus=\"battery\", e_cyclic=True, e_nom=100.0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "network.optimize()\n",
    "print(\"Objective:\", network.objective)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The optimal panel size in kW is"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "network.generators.p_nom_opt[\"PV panel\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "network.generators_t.p.plot.area(figsize=(9, 4))\n",
    "plt.tight_layout()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.DataFrame(\n",
    "    {attr: network.stores_t[attr][\"battery storage\"] for attr in [\"p\", \"e\"]}\n",
    ")\n",
    "df.plot(grid=True, figsize=(10, 5))\n",
    "plt.legend(labels=[\"Energy output\", \"State of charge\"])\n",
    "plt.tight_layout()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The losses in kWh per pay are:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(\n",
    "    network.generators_t.p.loc[:, \"PV panel\"].sum()\n",
    "    - network.loads_t.p.loc[:, \"driving\"].sum()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "network.links_t.p0.plot.area(figsize=(9, 5))\n",
    "plt.tight_layout()"
   ]
  }
 ],
 "metadata": {
  "@webio": {
   "lastCommId": null,
   "lastKernelId": null
  },
  "kernelspec": {
   "display_name": "",
   "language": "python",
   "name": ""
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
